package org.springcloud.wisdom.spring_02_classroom.websocket;


import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint(value = "/websocket/{username}")
@Component
public class WebSocketServer2 {

    static Logger log = LoggerFactory.getLogger(WebSocketServer2.class);

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer2> webSocketSet = new CopyOnWriteArraySet<WebSocketServer2>();

    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据（发送的中介工具）
    private Session session;

    /**
     * 连接建立成功调用的方法
     */
    //之前用的都是webSocketSet方法存取session，发送和接受在线人数
    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        addOnlineCount();           //在线数加1
        log.info("有新连接加入！当前在线人数为" + getOnlineCount());
        System.out.println("进入onOpen方法,websocket已启动："+username+"欢迎您！");
        //下面是新方法
        sessionMap.put(username, session);
////        log.info("有新用户加入，username={}, 当前在线人数为：{}", username, sessionMap.size());
        JSONObject result = new JSONObject();
        JSONArray array = new JSONArray();
        result.set("users",array);
        for (Object key : sessionMap.keySet()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("username", key);
            // {"username", "zhang", "username": "admin"}
            array.add(jsonObject);
        }
//        {"users": [{"username": "zhang"},{ "username": "admin"}]}
        try {
            //把这里改成传一个 session  和 username 的集合，就可以把在线用户发送给前端
            sendMessage(JSONUtil.toJsonStr(result));  // 后台发送消息给所有的客户端(把所有上线用户传给前端）
//            sendMessage("链接成功");  // 后台发送消息给所有的客户端(把所有上线用户传给前端）
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
//    @OnMessage
//    public void onMessage(String message, Session session) {
//        System.out.println("进入onMessage方法");
//        log.info("来自客户端的消息:" + message);
//        //群发消息
//        for (WebSocketServer2 item : webSocketSet) {
//            try {
//                item.sendMessage(message);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
//    }
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("username") String username) {
        System.out.println("进入onMessage方法");
        //message中把to的对象偷偷藏进来，然后发消息的时候单发给它就行
        //这里的取出名字，是为了找到tosession，找到发过去的接口
        JSONObject obj = JSONUtil.parseObj(message);
        String toUsername = obj.getStr("to"); // to表示发送给哪个用户，比如 admin
        log.info("服务端收到用户username"+username+"的消息:"+message+"发送给："+toUsername);
        System.out.println("Tousername"+toUsername);
        String content = obj.getStr("content"); // 发送的消息文本  hello
        Integer ifchange = obj.getInt("ifchange"); // 发送的消息文本  hello
        // {"to": "admin", "text": "聊天文本"}
        if (toUsername != null && toUsername.trim().length() > 0) {
            log.info("这是一条私发消息");
            // 服务器端 再把消息组装一下，组装后的消息包含发送人和发送的文本内容
            // {"from": "zhang", "text": "hello"}
            Session toSession = sessionMap.get(toUsername); // 根据 to用户名来获取 session，再通过session发送消息文本
            JSONObject jsonObject = new JSONObject();
            jsonObject.set("from", username);  // from 是 zhang
            jsonObject.set("content", content);  // text 同上面的text
            jsonObject.set("to", toUsername);  // text 同上面的text
            jsonObject.set("ifchange", ifchange);  // text 同上面的text
            this.sendMessage2(jsonObject.toString(), toSession);
            log.info("发送给用户username={}，消息：{}", toUsername, jsonObject.toString());
        } else {
            log.info("这是一条群发消息");
//            for (WebSocketServer2 item : webSocketSet) {
//                try {
//                    item.sendMessage(message);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
        }
//        log.info("来自客户端的消息:" + message);
//        //群发消息
//        for (WebSocketServer2 item : webSocketSet) {
//            try {
//                item.sendMessage(message);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }


    public void sendMessage(String message) throws IOException {
        //群聊呢
        System.out.println("进入了sendMessage方法");
        System.out.println(message);
        session.getBasicRemote().sendText(message);



//        try {
//            for (Session session : sessionMap.values()) {
//                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
//                session.getBasicRemote().sendText(message);
//            }
//        } catch (Exception e) {
//            log.error("服务端发送消息给客户端失败", e);
//        }
    }

    private void sendMessage2(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (Exception e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }



    /**
     * 群发自定义消息
     * */
    public static void sendInfo(String message) throws IOException {
        log.info(message);
        for (WebSocketServer2 item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer2.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer2.onlineCount--;
    }
}
